using System;
using System.Diagnostics;
using NUnit.Framework;

namespace seanfoy.oopsnet {
    public abstract class TestExe {
        abstract protected string progUnderTest();

        [Test]
        public void exitStatus() {
            string imageName = progUnderTest();
            launch(imageName, new string [] {}, assertExitsNormally);
            launch(imageName, new string [] {"crash"}, assertExitsAbnormally);
        }

        public delegate void TestProcess(Process p);

        public void launch(string imageName, string [] args, TestProcess investigate) {
            ProcessStartInfo pi = new ProcessStartInfo();
            pi.UseShellExecute = false;
            pi.CreateNoWindow = true;
            pi.RedirectStandardError = true;
            pi.FileName = imageName;
            string [] quotedArgs = new string[args.Length];
            for (int i = 0; i < args.Length; ++i) {
                quotedArgs[i] =
                    String.Format(
                        "\"{0}\"",
                        args[i].Replace("\\", "\\\\").Replace("\"", "\\\""));
            }
            pi.Arguments = String.Join(" ", args);
            using (Process p = Process.Start(pi)) {
                investigate(p);
            }
        }

        public static void _assertExitsNormally(Process p) {
            p.StandardError.ReadToEnd();
            p.WaitForExit();
            Assert.AreEqual(0, p.ExitCode, "An app ought to be able to run normally");
        }
        public static TestProcess assertExitsNormally = new TestProcess(_assertExitsNormally);
        public static void _assertExitsAbnormally(Process p) {
            string stderr = p.StandardError.ReadToEnd();
            p.WaitForExit();
            Assert.AreEqual(1, p.ExitCode, "The app should not have exited normally.");
            Assert.IsNotNull(stderr, "The app should leave some indication of the problem on standard output.");
            Assert.AreNotEqual(String.Empty, stderr, "The app should leave some indication of the problem on standard output.");
        }
        public static TestProcess assertExitsAbnormally = new TestProcess(_assertExitsAbnormally);
    }
}
